package com.cq.hd.admin.shiro;

import com.cq.hd.admin.po.TbAdminUserPo;
import com.cq.hd.admin.service.TbAdminPermissionService;
import com.cq.hd.admin.service.TbAdminUserService;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.constant.RedisKeyConstant;
import com.cq.hd.common.enums.ExceptionEnum;
import com.cq.hd.common.utils.JwtUtil;
import com.cq.hd.common.utils.RedisUtil;
import com.cq.hd.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class TokenRealm extends AuthorizingRealm {

    @Resource
    private TbAdminUserService adminUserService;

    @Resource
    private TbAdminPermissionService adminPermissionService;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        // 获取保存在token中的userId
        String userId;
        try {
            userId = JwtUtil.getAudience(token, 0);
        } catch (Exception e) {
            log.error("token认证失败！token：{}", token);
            throw new AuthenticationException(ExceptionEnum.UNAUTHORIZED.getMsg());
        }

        // 获取Redis缓存中的用户登录密钥
        String loginKey = redisUtil.get(String.format(RedisKeyConstant.ADMIN_USER_LOGIN_KEY, userId));
        if (StringUtils.isNullOrEmpty(loginKey)) {
            log.error("token认证失败！token：{}", token);
            throw new AuthenticationException(ExceptionEnum.AUTH_TIME_OUT.getMsg());
        }

        // Token验证
        boolean flag = JwtUtil.tokenVerify(token, loginKey);
        if (!flag) {
            log.error("token认证失败！token：{}", token);
            throw new AuthenticationException(ExceptionEnum.UNAUTHORIZED.getMsg());
        }

        TbAdminUserPo adminUserPo = adminUserService.getById(userId);
        if (adminUserPo == null) {
            throw new UnknownAccountException("用户不存在");
        }

        if (adminUserPo.getStatus() == null || adminUserPo.getStatus() != 0) {
            throw new UnknownAccountException("您已被禁用");
        }

        // 重新设置登录失效时间
        redisUtil.expire(String.format(RedisKeyConstant.ADMIN_USER_LOGIN_KEY, userId), Constant.USER_LOGIN_TIMEOUT, TimeUnit.SECONDS);

        return new SimpleAuthenticationInfo(token, token, this.getName());
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        if (principalCollection == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
        String token = (String) getAvailablePrincipal(principalCollection);
        // 获取保存在token中的userId
        String userId = JwtUtil.getAudience(token, 0);
        TbAdminUserPo adminUserPo = adminUserService.getById(userId);
        Integer roleIds = adminUserPo.getRoleId();
        Set<String> roleSet = new HashSet<>();
        roleSet.add(roleIds.toString());
        Set<String> permissions = adminPermissionService.getSetByRoleIds(roleIds);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roleSet);
        simpleAuthorizationInfo.setStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }

}
